/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package fr.loof.fonzie;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.loof.fonzie.dialects.JPADialect;

/**
 * @author <a href="nicolas@apache.org">Nicolas De Loof</a>
 */
public class JPAUtils
{
    protected static Logger logger = LoggerFactory.getLogger( JPAUtils.class );

    /**
     * The active JPA implementation Dialect. Autodetected on class loading based on supported implementations. Maybe
     * overriden using {{@link #setJPADialect(JPADialect)}.
     */
    private static JPADialect dialect;
    static
    {
        for ( String className : JPADialect.SUPPORTED_DIALECTS )
        {
            try
            {
                dialect = (JPADialect) Class.forName( className ).newInstance();
                break;
            }
            catch ( Exception e )
            {
                //
            }
        }
    }

    /**
     * Configure a custom JPADialect, typically to use Fonzie with an unsupported JPA implementation (in such cas,
     * consider contribution please)
     */
    public static void setJPADialect( JPADialect dialect )
    {
        JPAUtils.dialect = dialect;
    }

    private JPAUtils()
    {
        super();
    }

    /**
     * Read the @Id attribute of an @Entity.
     * <p>
     * Internally delegates to an JPA implementation specific component, so that a lazy-loaded proxy may not require
     * initialization
     */
    public static Object getId( Object entity )
    {
        return dialect.getIdentifier( entity );
    }

    /**
     * Get the actual type of the entity, maybe a proxy on a superclass.
     * <p>
     * Internally delegates to an JPA implementation specific component
     */
    public static Class getActualType( Object entity )
    {
        return dialect.getActualType( entity );
    }

    /**
     * Extract (if necessary) the underlying object from a JPA proxy, so that it can be safelly used for type checking.
     * Be aware such un-proxied object is not managed anymore. Any data access / graph navigation NOT be under control
     * of the EntityManager and its data integrity / lazy-loading management.
     * <p>
     * Internally delegates to an JPA implementation specific component
     */
    public static <T> T getImplementation( T entity )
    {
        return dialect.getImplementation( entity );
    }

}
